{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "IndentationError",
     "evalue": "unindent does not match any outer indentation level (<tokenize>, line 28)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;36m  File \u001b[1;32m\"<tokenize>\"\u001b[1;36m, line \u001b[1;32m28\u001b[0m\n\u001b[1;33m    self.k=k\u001b[0m\n\u001b[1;37m    ^\u001b[0m\n\u001b[1;31mIndentationError\u001b[0m\u001b[1;31m:\u001b[0m unindent does not match any outer indentation level\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "data = pd.read_csv(r\"Iris.csv\",header=0)\n",
    "#显示前n行记录，默认n值为5data.head()\n",
    "#尾n行，data.tail()\n",
    "#随机抽取,默认抽取一条，可以通过参数进行指定样本数量\n",
    "\n",
    "\n",
    "data.sample(10)\n",
    "data[\"Species\"]=data[\"Species\"].map({\"virginica\":0,\"setosa\":1,\"versicolor\":2})\n",
    "#将类别文本映射成数据类型。\n",
    "\n",
    "data.drop(\"ID\",axis=1,inplace=True)\n",
    "#删掉ID列，axis=1代表是列，axis默认为0代表是行\n",
    "data.duplicated().any()\n",
    "data.drop_duplicates(inplace=True)\n",
    "#len(data)\n",
    "data['Species'].value_counts()\n",
    "#求长度\n",
    "\n",
    "\"\"\"使用python语言实现k近邻算法，实现分类\"\"\"\n",
    "class KNN:\n",
    "    \n",
    "    #k是选几个邻居\n",
    "def  __init__(self,k):\n",
    "        \"\"\"初始化方法\"\"\"\n",
    "         #使用k来初始化knn的k\n",
    "    self.k=k \n",
    "def fit(self,X,y): #knn是惰性算法,对于矩阵大写表示，对于向量小写\n",
    "            \"\"\"训练方法\n",
    "            parameters\n",
    "            X：类数组类型 （类似的数组类型，可以是list numpy—array类型 pandas\n",
    "            形状为[样本数量，特征数量] [147,4]\n",
    "            待训练的样本特征（属性） \n",
    "            y：类数组类型，形状为][样本数量]\n",
    "            每个样本的目标值（标签）\n",
    "            将x转换为ndarry数组类型\n",
    "            \"\"\"\n",
    "    self.X=np.asarray(X)\n",
    "    self.y=np.assaray(y)\n",
    "        \n",
    "def predict(self,X):\n",
    "        \"\"\"根据参数传递的样本，对样本数据进行预测\n",
    "        X：类数组类型，形状为：[样本数量，特征数量]\n",
    "            带训练的样本特征（属性）\n",
    "            \n",
    "        returns\n",
    "        \n",
    "        result:数组类型，预测的结果\n",
    "            \n",
    "        \"\"\"\n",
    "    X=np.asarray(X)\n",
    "    result=[] \n",
    "        #对ndarray数组进行遍历，每次取数组中的一哈昂\n",
    "        #ndarray可以进行整体运算一行对多行进行广播一样的操作。\n",
    "        \n",
    "    for x in X:\n",
    "            #对于ndarray数组进行遍历，每次取数组的一行\n",
    "            dis= np.sqrt(np.sum(x-self.X)**2,axis=1)\n",
    "            #dis.sort是不行的，我还需要知道它原本位置在哪。\n",
    "            index=dis.argsort()\n",
    "            #进行阶段，只取前k个元素【去距离最近的k个元素\n",
    "            index = index[:self.k]\n",
    "            count= np.bincount(self.y[index])#np.bincount返回数组中每个元素出现的次数，元素必须是非负的整数\n",
    "            #返回ndarray数组中，值最大的元素对应的索引\n",
    "            #最大元素就是出现次数最多的元素\n",
    "            result.append(count.argmax())  #已经使用argmax求出来了，加入到result[]列表中\n",
    "        return np.asarray(result) \n",
    "\n",
    "    \n",
    "#提取出每个类别鸢尾花的数据\n",
    "t0 = data[data[\"Species\"]==0]\n",
    "t1 = data[data[\"Species\"]==1]\n",
    "t2 = data[data[\"Species\"]==2]\n",
    "\n",
    "#对每个类别进行洗牌 #指定数据集的数量,random_state打乱顺序还希望顺序回复)\n",
    "t0 = t0.sample(len(t0),random_state=0)\n",
    "t1 = t1.sample(len(t1),random_state=0)\n",
    "t0 = t2.sample(len(t2),random_state=0)\n",
    "#构建训练集和测试集\n",
    "\n",
    "#假设前30行当作训练集，需要切割行和列，训练X不应该包括类别，只需要除标签之外的当作特征属性。\n",
    "train_X=pd.concat([t0.iloc[:30,:-1],t1.iloc[:30,:-1],t1.iloc[:30,:-1]],axis=0)\n",
    "train_y=pd.concat([t0.iloc[:30,-1],t1.iloc[:30,-1],t1.iloc[:30,-1]],axis=0)\n",
    "test_X=pd.concat([t0.iloc[30:,:-1],t1.iloc[30:,:-1],t1.iloc[30:,:-1]],axis=0)\n",
    "test_y=pd.concat([t0.iloc[30:,-1],t1.iloc[30:,-1],t1.iloc[30:,-1]],axis=0)\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "#创建KNN对象进行训练与测试\n",
    "\n",
    "\n",
    "\n",
    "knn = KNN(k=3)#假设现在有3个邻居来测试鸢尾花\n",
    "knn.fit(train_X,train_y)\n",
    "result=knn.predict(test_X)\n",
    "#可以使用print和display输出\n",
    "display(result)\n",
    "display(test_y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "      ID  Sepal.Length  Sepal.Width  Petal.Length  Petal.Width     Species\n",
      "80    81           5.5          2.4           3.8          1.1  versicolor\n",
      "141  142           6.9          3.1           5.1          2.3   virginica\n",
      "123  124           6.3          2.7           4.9          1.8   virginica\n",
      "35    36           5.0          3.2           1.2          0.2      setosa\n",
      "121  122           5.6          2.8           4.9          2.0   virginica\n",
      "47    48           4.6          3.2           1.4          0.2      setosa\n",
      "146  147           6.3          2.5           5.0          1.9   virginica\n",
      "120  121           6.9          3.2           5.7          2.3   virginica\n",
      "11    12           4.8          3.4           1.6          0.2      setosa\n",
      "136  137           6.3          3.4           5.6          2.4   virginica\n",
      "150\n",
      "鸢尾花测试集test_y中样本分类正确的个数:\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "57"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "鸢尾花数据集test_y中分类的正确率:\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.95"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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q9XZ2alnn31WN9xwg66++mpdffXVWrVqlSTp9ttv1+zZs/Xoo4/qsMMO0/e+971Bn6+zs1NXXHGFHnroIW3evFmvvvpq0c8JAAAAACDcksnC2lHeQjEyqH3r4FHkUO2jMXv2bC1cuHDYfY455hjNnj1bn/zkJ3XYYYfpzDPP1PLly/fazzm3134bN25US0uLmpub9dZbb6mjo0NHHnnkXj/7wgsv7KnjhBNO0P3336/LLrtsr+cbM2aM7rjjDt1555164403tH379uKcCAAAAABAZGQy3hpBfaeKJRJeOypPKEYGJccPHkUO1T4aBx100D73eeaZZ3TyySfrwQcf1JtvvqnHHntsxPt99KMf1VVXXaXm5mZ961vfUjIfs44bN07d+avOOadZs2ZpzZo1krzRSrNmzRr0+VasWKHzzz9fd999tw488MAinQUAAAAAQJQ0NEhNTVJtrWTmbZuavHZUnlCEQZkFGSXGJPq1JcYklFkQTESZSqV0880366STTlJXV5fq6+tHvN+ll16q+++/X/PmzdN3v/tdfehDH5IknX766frxj3+sk08+WY899pguueQSPf/885o3b55+85vf6OKLLx70+U4//XTdcMMNOvXUUyVJHR0dJTsPAAAAAIDwaGiQNm+Wenq8LUFQ5TLnXNA1qL6+3rW2tvZre/HFFzVz5swRP0d2Q1aNqxrVvrVdyfFJZRZkir54NEam0NcOAAAAAAAUn5mtc87tNUIlFGsGSd5dwwh/AAAAAAAAhheKaWIAAAAAAAAYGcIgAAAAAACACCEMAgAAAAAAiBDCIAAAAAAAgAghDNqH6dOnj2i/q666qqj9jub5Rvqzxa4ZAAAAAACUv9CEQdmslEpJsZi3zWZL2/+yZcvK5vlG+rPFrhkAAAAAAJS/UIRB2ayUTkttbZJz3jad9icQmj9/vr72ta/pjDPO2Ku91/bt23X22Wdr3rx5+uxnP6tdu3YN+lyZTEY//elPJUk33HCD7rnnnkGfb7B+t2/frk996lOaM2eOvvCFL+j6668f9GevueYaNTY2at68eTr66KPV1dU16H47duzQhRdeqLlz5+rss89Wd3e3tm3bpjPPPFMf//jHtWjRopGcHgAAAAAAUOZCEQY1Nkrd3f3buru99mJbs2aNTjzxRK1cuXLIfV544QXFYjGtXr1aixYt0rZt23TZZZdp/vz5e/5dd911uuCCC3T//fdLklavXq2zzjprxP2+9NJLmjp1qh5//HFt2rRJ3/jGN4b82U2bNmn16tVauHChHn744UH3aWpq0lFHHaXHH39c5513np577jl1dnbqiiuu0EMPPaTNmzfr1VdfHckpAgAAAACEzNSWFp1230ZNPWpnYDNyUDzVQRdQDO3thbWPxuzZs7Vw4cJh9znmmGM0e/ZsffKTn9Rhhx2mM888U8uXLx903y1btujtt9/WIYccogMPPHDE/dbU1GjdunWaN2+errzyymHrueiiiyRJyWRSuVxu0H1eeuklnXfeeZKkiy++WJLU1tamO+64Q3feeafeeOMNbd++fdh+AAAAAADh1JHLqSPeJd34qnT/RLXdlVI6PVaS1NAQcHEoWChGBiWThbWPxkEHHbTPfZ555hmdfPLJevDBB/Xmm2/qscceG3Lf448/XsuWLdM555xTUL8PPPCAli5dqieffFIN+7jyhguZeh1++OH69a9/LUm6/vrrdccdd2jFihU6//zzdffdd4/oOQAAAAAAIRZ30tge6awu6Ydr1X3pRv3NjTuDrgr7IRRhUCYjJRL92xIJrz0IqVRKN998s0466SR1dXWpvr5+yH0vuOACLVu2TGeffXZBfdTV1emKK67QqaeeqgsvvFDPPffcqGq+9NJL9dRTT2n+/Pl66qmn9MUvflGnn366brjhBp166qmSpI6OjlH1AQAAAAAIgd5Q6JxOdXx9fdDVYD+Ycy7oGlRfX+9aW1v7tb344ouaOXPmiJ8jm/XWCGpv90YEZTLhHqp2++236+6779aYMWM0ZswYffWrX91r0emgFPraAQAAAADKmzU3v/cgZ1KPSQ9M0tRHavW/z4wNrC4Mz8zWOef2GqESijWDJC/4CXP4M9Cll16qSy+9NOgyAAAAAABR0ScE0vdrldg5Vv/QFHRR2B+hCYMAAAAAAIA/auJxHb5tgjY21qpjw9hIzMgJM8IgAAAAAAAwrC0nneR9UdhytyhToVhAGgAAAACAKJna0qIlGzeqcyd380LhCIMAAAAAAKgwHbmcVnR1adratYRCKBhh0H646qqrhv3+Nddco+a+K63nPf3003r66ad9qQkAAAAAEC0557Sjp4dQCAULRRhU6uFxy5Yt26+fIwwCAAAAABRbbyi0vLNTc9evD7ocVIBQLCDd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\n",
      "text/plain": [
       "<Figure size 1440x720 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "data = pd.read_csv(r\"iris.csv\", header=0)\n",
    "# data.head(10)\n",
    "# data.tail(10)\n",
    "print(data.sample(10))\n",
    "data[\"Species\"] = data[\"Species\"].map({\"versicolor\":0,\"setosa\":1,\"virginica\":2}) # 类别名称映射为数字\n",
    "# data = data.drop(\"Id\",axis=1)  # 删除列\n",
    "print(len(data))\n",
    "if data.duplicated().any(): # 重复值\n",
    "    data.drop_duplicates(inplace=True) #删除重复值\n",
    "    print(len(data))\n",
    "data[\"Species\"].value_counts()  # 查看各个类别的鸢尾花记录\n",
    "\n",
    "class KNN:\n",
    "    '''使用KNN实现K近邻算法实现分类'''\n",
    "    def __init__(self, k):\n",
    "        '''初始化\n",
    "        \n",
    "        Parameters\n",
    "        -----\n",
    "        k:int\n",
    "            邻居个位数\n",
    "        \n",
    "        '''\n",
    "        self.k = k\n",
    "    def fit(self, X, y):\n",
    "        '''训练\n",
    "        \n",
    "        Parameeters\n",
    "        -----\n",
    "        X: 类数组类型，可以是List也可以是Ndarray，形状为： [样本数量,特征数量]\n",
    "        y: 类数组类型，形状为：[样本数量]\n",
    "        \n",
    "        '''\n",
    "        self.X = np.asarray(X) #转换为ndarray类型\n",
    "        self.y = np.asarray(y)\n",
    "    def predict(self, X):\n",
    "        '''对样本进行预测\n",
    "        Parameters:\n",
    "        X: 类数组类型，可以是List也可以是Ndarray，形状为： [样本数量,特征数量]\n",
    "        Returns:\n",
    "        数组类型，预测结果\n",
    "        '''\n",
    "        X = np.asarray(X)\n",
    "        result = []\n",
    "        for x in X:\n",
    "            dis = np.sqrt(np.sum((x-self.X)**2, axis=1)) # 对于测试机的每隔一个样本，一次与训练集的所有数据求欧氏距离\n",
    "            index = dis.argsort()# 返回排序结果的下标\n",
    "            index = index[:self.k] # 截取前K个\n",
    "            count = np.bincount(self.y[index]) # 返回数组中每个整数元素出现次数，元素必须是非负整数\n",
    "            result.append(count.argmax()) # 返回ndarray中值最大的元素所对应的索引，就是出现次数最多的索引，也就是我们判定的类别\n",
    "        return np.asarray(result)\n",
    "    def predict2(self, X):\n",
    "        '''对样本进行预测，加入权重计算\n",
    "        Parameters:\n",
    "        X: 类数组类型，可以是List也可以是Ndarray，形状为： [样本数量,特征数量]\n",
    "        Returns:\n",
    "        数组类型，预测结果\n",
    "        '''\n",
    "        X = np.asarray(X)\n",
    "        result = []\n",
    "        for x in X:\n",
    "            dis = np.sqrt(np.sum((x-self.X)**2, axis=1)) # 对于测试机的每隔一个样本，一次与训练集的所有数据求欧氏距离\n",
    "            index = dis.argsort()# 返回排序结果的下标\n",
    "            index = index[:self.k] # 截取前K个\n",
    "            count = np.bincount(self.y[index], weights=1/dis[index]) # 返回数组中每个整数元素出现次数，元素必须是非负整数\n",
    "            result.append(count.argmax()) # 返回ndarray中值最大的元素所对应的索引，就是出现次数最多的索引，也就是我们判定的类别\n",
    "        return np.asarray(result)\n",
    "    \n",
    "# 提取每个类中鸢尾花数据\n",
    "t0 = data[data[\"Species\"]==0]\n",
    "t1 = data[data[\"Species\"]==1]\n",
    "t2 = data[data[\"Species\"]==2]\n",
    "# 打乱# 打乱每个类别数据\n",
    "t0 = t0.sample(len(t0), random_state=0)\n",
    "t1 = t1.sample(len(t1), random_state=0)\n",
    "t2 = t2.sample(len(t2), random_state=0)\n",
    "# 分配训练集和数据集，axis=0表示按纵向方式拼接\n",
    "train_X = pd.concat([t0.iloc[:30, :-1], t1.iloc[:30, :-1], t2.iloc[:30, :-1]], axis=0)\n",
    "train_y = pd.concat([t0.iloc[:30, -1], t1.iloc[:30, -1], t2.iloc[:30, -1]], axis=0)\n",
    "test_X = pd.concat([t0.iloc[30:, :-1], t1.iloc[30:, :-1], t2.iloc[30:, :-1]], axis=0)\n",
    "test_y = pd.concat([t0.iloc[30:, -1], t1.iloc[30:, -1], t2.iloc[30:, -1]], axis=0)\n",
    "\n",
    "knn = KNN(k=30)\n",
    "knn.fit(X=train_X, y=train_y)\n",
    "result = knn.predict(test_X)\n",
    "#display(result)\n",
    "#display(test_y)\n",
    "#display(result==test_y)\n",
    "\n",
    "print(\"鸢尾花测试集test_y中样本分类正确的个数:\")\n",
    "display(np.sum(result == test_y))\n",
    "print(\"鸢尾花数据集test_y中分类的正确率:\")\n",
    "display(np.sum(result==test_y)/len(result))\n",
    "\n",
    "# \"Iris-versicolor\":0,\"Iris-setosa\":1,\"Iris-virginica\":2\n",
    "\n",
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "#默认情况下，matplotlib不支持中文\n",
    "#设置字体为黑体，设置在中文字体时候，能够正常显示符号\n",
    "mpl.rcParams[\"font.family\"]=\"SimHei\"\n",
    "mpl.rcParams[\"axes.unicode_minus\"]=False\n",
    "\n",
    "# \"Iris-versicolor\":0,\"Iris-setosa\":1,\"Iris-virginica\":2\n",
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "plt.figure(figsize=(20,10))\n",
    "mpl.rcParams[\"font.family\"] = 'SimHei' # 默认mpl不支持中文，设置一下支持 \n",
    "mpl.rcParams[\"axes.unicode_minus\"] = False # 设置中文字体是可以正常显示负号\n",
    "plt.scatter(x=t0[\"Sepal.Length\"][:30], y=t0[\"Petal.Length\"][:30], color='r', label=\"Iris-versicolor\")\n",
    "plt.scatter(x=t1[\"Sepal.Length\"][:30], y=t1[\"Petal.Length\"][:30], color='g', label=\"Iris-setosa\")\n",
    "plt.scatter(x=t2[\"Sepal.Length\"][:30], y=t2[\"Petal.Length\"][:30], color='b', label=\"Iris-virginica\")\n",
    "right = test_X[result == test_y]\n",
    "wrong = test_X[result != test_y]\n",
    "plt.scatter(x=right[\"Sepal.Length\"], y=right[\"Petal.Length\"], color='c', label=\"right\", marker=\">\")\n",
    "plt.scatter(x=wrong[\"Sepal.Length\"], y=wrong[\"Petal.Length\"], color='m', label=\"wrong\", marker=\"x\")\n",
    "plt.xlabel('花萼长度')\n",
    "plt.ylabel('花瓣长度')\n",
    "plt.title('KNN算法鸢尾花分类结果')\n",
    "plt.legend(loc='best')\n",
    "plt.show()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "ImportError",
     "evalue": "\n\nIMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!\n\nImporting the numpy C-extensions failed. This error can happen for\nmany reasons, often due to issues with your setup or how NumPy was\ninstalled.\n\nWe have compiled some common reasons and troubleshooting tips at:\n\n    https://numpy.org/devdocs/user/troubleshooting-importerror.html\n\nPlease note and check the following:\n\n  * The Python version is: Python3.7 from \"D:\\Anaconda3\\envs\\pytorch_gpu\\python.exe\"\n  * The NumPy version is: \"1.21.5\"\n\nand make sure that they are the versions you expect.\nPlease carefully study the documentation linked above for further help.\n\nOriginal error was: DLL load failed: 找不到指定的模块。\n",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mImportError\u001b[0m                               Traceback (most recent call last)",
      "\u001b[1;32mD:\\Anaconda3\\envs\\pytorch_gpu\\lib\\site-packages\\numpy\\core\\__init__.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     21\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 22\u001b[1;33m     \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mmultiarray\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     23\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mImportError\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mexc\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\Anaconda3\\envs\\pytorch_gpu\\lib\\site-packages\\numpy\\core\\multiarray.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 12\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0moverrides\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     13\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0m_multiarray_umath\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\Anaconda3\\envs\\pytorch_gpu\\lib\\site-packages\\numpy\\core\\overrides.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      6\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 7\u001b[1;33m from numpy.core._multiarray_umath import (\n\u001b[0m\u001b[0;32m      8\u001b[0m     add_docstring, implement_array_function, _get_implementing_args)\n",
      "\u001b[1;31mImportError\u001b[0m: DLL load failed: 找不到指定的模块。",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001b[1;31mImportError\u001b[0m                               Traceback (most recent call last)",
      "\u001b[1;32mC:\\Windows\\Temp\\ipykernel_4848\\943604275.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mimport\u001b[0m \u001b[0mnumpy\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      2\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mpandas\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mpd\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34mr\"Iris.csv\"\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mheader\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msample\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[1;31m#将类别文本映射成数据类型。\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\Anaconda3\\envs\\pytorch_gpu\\lib\\site-packages\\numpy\\__init__.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m    148\u001b[0m     \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0m_distributor_init\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    149\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 150\u001b[1;33m     \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mcore\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    151\u001b[0m     \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m\u001b[0mcore\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[1;33m*\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    152\u001b[0m     \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mcompat\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\Anaconda3\\envs\\pytorch_gpu\\lib\\site-packages\\numpy\\core\\__init__.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     46\u001b[0m \"\"\" % (sys.version_info[0], sys.version_info[1], sys.executable,\n\u001b[0;32m     47\u001b[0m         __version__, exc)\n\u001b[1;32m---> 48\u001b[1;33m     \u001b[1;32mraise\u001b[0m \u001b[0mImportError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     49\u001b[0m \u001b[1;32mfinally\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     50\u001b[0m     \u001b[1;32mfor\u001b[0m \u001b[0menvkey\u001b[0m \u001b[1;32min\u001b[0m \u001b[0menv_added\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mImportError\u001b[0m: \n\nIMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!\n\nImporting the numpy C-extensions failed. This error can happen for\nmany reasons, often due to issues with your setup or how NumPy was\ninstalled.\n\nWe have compiled some common reasons and troubleshooting tips at:\n\n    https://numpy.org/devdocs/user/troubleshooting-importerror.html\n\nPlease note and check the following:\n\n  * The Python version is: Python3.7 from \"D:\\Anaconda3\\envs\\pytorch_gpu\\python.exe\"\n  * The NumPy version is: \"1.21.5\"\n\nand make sure that they are the versions you expect.\nPlease carefully study the documentation linked above for further help.\n\nOriginal error was: DLL load failed: 找不到指定的模块。\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "data = pd.read_csv(r\"Iris.csv\",header=0)\n",
    "data.sample(10)\n",
    "#将类别文本映射成数据类型。\n",
    "data[\"Species\"]=data[\"Species\"].map({\"virginica\":0,\"setosa\":1,\"versicolor\":2})\n",
    "data.drop(\"ID\",axis=1,inplace=True)#删掉ID列\n",
    "data.duplicated().any()\n",
    "data.drop_duplicates(inplace=True)\n",
    "data['Species'].value_counts()\n",
    "data.sample(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'data' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32mC:\\Windows\\Temp\\ipykernel_4848\\2215065083.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m#提取出每个类别鸢尾花的数据\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mt0\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m\"Species\"\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m==\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[0mt1\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m\"Species\"\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m==\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[0mt2\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m\"Species\"\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m==\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'data' is not defined"
     ]
    }
   ],
   "source": [
    "#提取出每个类别鸢尾花的数据\n",
    "t0 = data[data[\"Species\"]==0]\n",
    "t1 = data[data[\"Species\"]==1]\n",
    "t2 = data[data[\"Species\"]==2]\n",
    "\n",
    "#对每个类别进行洗牌 \n",
    "t0 = t0.sample(len(t0),random_state=0)\n",
    "t1 = t1.sample(len(t1),random_state=0)\n",
    "t0 = t2.sample(len(t2),random_state=0)\n",
    "#构建训练集和测试集\n",
    "\n",
    "#假设前40行当作训练集，需要切割行和列，训练X不应该包括类别，只需要除标签之外的当作特征属性。\n",
    "train_X=pd.concat([t0.iloc[:40,:-1],t1.iloc[:40,:-1],t1.iloc[:40,:-1]],axis=0)\n",
    "train_y=pd.concat([t0.iloc[:40,-1],t1.iloc[:40,-1],t1.iloc[:40,-1]],axis=0)\n",
    "test_X=pd.concat([t0.iloc[40:,:-1],t1.iloc[40:,:-1],t1.iloc[40:,:-1]],axis=0)\n",
    "test_y=pd.concat([t0.iloc[40:,-1],t1.iloc[40:,-1],t1.iloc[40:,-1]],axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "      ID  Sepal.Length  Sepal.Width  Petal.Length  Petal.Width     Species\n",
      "70    71           5.9          3.2           4.8          1.8  versicolor\n",
      "35    36           5.0          3.2           1.2          0.2      setosa\n",
      "97    98           6.2          2.9           4.3          1.3  versicolor\n",
      "148  149           6.2          3.4           5.4          2.3   virginica\n",
      "133  134           6.3          2.8           5.1          1.5   virginica\n",
      "1      2           4.9          3.0           1.4          0.2      setosa\n",
      "98    99           5.1          2.5           3.0          1.1  versicolor\n",
      "57    58           4.9          2.4           3.3          1.0  versicolor\n",
      "89    90           5.5          2.5           4.0          1.3  versicolor\n",
      "142  143           5.8          2.7           5.1          1.9   virginica\n",
      "150\n"
     ]
    },
    {
     "data": {
      "image/png": "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mRNzBk3l8ccfz+joaB599NFWt8I0POlJT8qiRYuyYMGCVrcCAAAATGHOhkGjo6N5ylOekkajkVJKq9vhMFRVlR//+McZHR3NM57xjFa3AwAAAExhzl4m9uijj+bXfu3XBEHzSCklv/Zrv+ZsLgAAAJjD5mwYlEQQNA/5nQEAAMDcNqfDIAAAAABmVvuEQYODSaORdHRMfB8cnJHVnnLKKYe13OWXXz4j482EI+ll1apVM9YHAAAAMPfM2Qmkp2VwMOntTcbGJh6PjEw8TpLVq2elhXXr1s3KOIdjLvUCAAAAzC3tcWbQ2rW/DIJ2GRubqM+wVatW5b3vfW9e8YpX7Fff5ZFHHslFF12UlStX5rWvfW127Ngx5br6+/vz+c9/Pkny4Q9/OJ/97GczNjaW17/+9Vm5cmXe+c53HnDcg42xZy+PPvpo3vjGN2bFihW56KKLMjY2lsceeyy/+7u/m5e+9KVZvXp1tm/fPmV/B1ruQPsAAAAAmPuaEgaVUtaUUjZOft1WSvl4M8bZbcuW6dWPwC233JIXvvCFuf766w+4zF133ZWOjo7ceOONufTSS/Pwww/nHe94R1atWrX768orr8wb3vCGXHfddUmSG2+8Ma961asyMDCQpUuX5sYbb8z999+f7373u1OOO9UYUxkYGMjznve8DA0N5XWve12+973v5eqrr87SpUvz9a9/Paeeemo++clPTvnaAy13OPsAAAAAmJuacplYVVUbkmxIklLKf0jyl80YZ7fFiycuDZuqPsOWLl2aSy655KDLnHnmmVm6dGle/vKX59RTT82FF16Yj3986jxsdHQ0P//5z/PUpz41Rx99dO65557cfPPN2bhxY372s59l69atee5zn7vfuFONMZW77747r3vd65Ikb33rW5Mk//k//+fd6zr33HN3B1L7uuuuu6Zc7nD2AQAAADA3NfUysVLKyUlOqKpqUzPHSX9/0t29d627e6I+w4455phDLnP77bfnxS9+cb7yla/kpz/9aW666aYDLnv22Wdn3bp1ec1rXpMkedaznpXLL788GzduzJ//+Z9n8WSgte+4hzvGs5/97Hz7299OknzoQx/KNddckyVLluSWW25JMnGWz5IlS6Z87YGWO5x9AAAAAMxNzZ4z6J2ZPENoX6WU3lLKplLKpgcffPDIRlm9OhkYSHp6klImvg8MzNrk0ftqNBr56Ec/mhe96EV54IEHsnz58gMu+4Y3vCHr1q3LRRddlCS57LLLct1112XlypX52Mc+lt/4jd84ojEuu+yyfOc738mqVavyne98J29+85vz9re/PXfeeWdWrlyZH/zgB7vPGNrX4S4HAAAAzB+lqqrmrLiUjiT/mORF1SEGWb58ebVp094nD33/+9/P6aef3pTeaC6/OwAAAGi9Usrmqqr2O3ukmWcGvSTJNw8VBAEAAAAwe5oZBr0iyY1NXD8AAAAA09SUu4klSVVV72/WugEAAAB4Ypo9gTQAAADQBgb7htLoGk1H2ZlG12gG+4Za3RJPUNPODAIAAADaw2DfUHo3LMtYjk6SjIwvSu+G45IMZfX6Fa1tjmlrmzODBu8YTGNdIx0f7EhjXSODdwzOyHpPOeWUw1ru8ssvn5HxDuS2227Lbbfd1tQxAAAAYCprBxq7g6BdxnJ01g40WtMQR6QtzgwavGMwvdf2ZuzxsSTJyEMj6b22N0my+ozVs9LDunXrmrr+XUHQ85///KaOAwAAAPvaMn7StOrMbW1xZtDaG9buDoJ2GXt8LGtvWDvjY61atSrvfe9784pXvGK/+i6PPPJILrrooqxcuTKvfe1rs2PHjinXNdVyY2Njef3rX5+VK1fmne98Z5Lkj//4j3PVVVflqquuyvnnn58keeyxx/K7v/u7eelLX5rVq1dn+/btU67v4YcfzoUXXpiXvOQlufTSS2d8fwAAAND+FnfeN606c1tbhEFbHtoyrfqRuOWWW/LCF74w119//QGXueuuu9LR0ZEbb7wxl156aR5++OG84x3vyKpVq3Z/XXnllVMuNzAwkKVLl+bGG2/M/fffn+9+97v58Ic/nPe973153/velxtuuCFJcvXVV2fp0qX5+te/nlNPPTWf/OQnp1zf/fffn3e961356le/muHh4fzoRz+a8X0CAABAe+vvHU53tu1V68629PcOt6YhjkhbXCa2+NjFGXloZMr6TFu6dGkuueSSgy5z5plnZunSpXn5y1+eU089NRdeeGE+/vGP77dcVVX7LXfPPffk5ptvzsaNG/Ozn/0sW7duzXOf+9z9XnvXXXft7uPcc8/Nddddl3e84x37rW/BggW55ppr8qlPfSo/+clP8sgjj8zMjgAAAKA2JiaJHsragUa2jJ+UxZ33pb932OTR81RbnBnUf35/uhd071XrXtCd/vP7Z3ysY4455pDL3H777Xnxi1+cr3zlK/npT3+am2666bCXe9aznpXLL788GzduzJ//+Z9n8eKJQOvJT35yxsYmLoWrqipLlizJLbfckmTibKUlS5ZMub5PfOITef3rX5/PfOYzOfroo6fsAwAAAA5l9foVGd6xKDurjgzvWCQImsfaIgxafcbqDFw8kJ5je1JS0nNsTwYuHpi1yaP31Wg08tGPfjQvetGL8sADD2T58uWHvdxll12W6667LitXrszHPvax/MZv/EaS5GUve1k+97nP5cUvfnFuuummvP3tb8+dd96ZlStX5gc/+EHe+ta3Trm+l73sZfnwhz+c8847L0mydevWWdsPAAAAwNxTqqpqdQ9Zvnx5tWnTpr1q3//+93P66ae3qCOOhN8dAAAAtF4pZXNVVfudodIWZwYBAAAAcHiEQQAAAAA1IgwCAAAAqBFhEAAAAECNCIMAAAAAaqRtwqDBwaTRSDo6Jr4PDs7Mek855ZTDWu7yyy+fmQFnYH2H+9qZ7hkAAACY+9ri1vKDg0lvbzI29stad3cyMJCsXn1kvZ1yyim59957j2wlNePW8gAAANB6bX1r+bVr9w6CkonHa9fO/FirVq3Ke9/73rziFa/Yr77LI488kosuuigrV67Ma1/72uzYsWPKdfX39+fzn/98kuTDH/5wPvvZz065vqnGfeSRR/LKV74y55xzTt70pjflQx/60JSv/cAHPpC1a9dm5cqVef7zn58HHnhgyuUeffTRvPGNb8yKFSty0UUXZWxsLA8//HAuvPDCvOQlL8mll156OLsHAACANtW3ZGO6yo6UUqWr7Ejfko2tboknqC3CoC1bplc/Erfcckte+MIX5vrrrz/gMnfddVc6Ojpy44035tJLL83DDz+cd7zjHVm1atXuryuvvDJveMMbct111yVJbrzxxrzqVa867HHvvvvuLFq0KENDQ7n33nvz/ve//4Cvvffee3PjjTfmkksuyde+9rUplxkYGMjznve8DA0N5XWve12+973v5f7778+73vWufPWrX83w8HB+9KMfHc4uAgAAoM30LdmYDXe9NOPpSlIynq5suOulAqF5qqvVDcyExYuTkZGp6zNt6dKlueSSSw66zJlnnpmlS5fm5S9/eU499dRceOGF+fjHPz7lsqOjo/n5z3+epz71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\n",
      "text/plain": [
       "<Figure size 1440x720 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "data = pd.read_csv(r\"iris.csv\", header=0)\n",
    "# data.head(10)\n",
    "# data.tail(10)\n",
    "print(data.sample(10))\n",
    "data[\"Species\"] = data[\"Species\"].map({\"versicolor\":0,\"setosa\":1,\"virginica\":2}) # 类别名称映射为数字\n",
    "# data = data.drop(\"Id\",axis=1)  # 删除列\n",
    "print(len(data))\n",
    "if data.duplicated().any(): # 重复值\n",
    "    data.drop_duplicates(inplace=True) #删除重复值\n",
    "    print(len(data))\n",
    "data[\"Species\"].value_counts()  # 查看各个类别的鸢尾花记录\n",
    "\n",
    "class KNN:\n",
    "    '''K近邻算法实现分类'''\n",
    "    def __init__(self, k):\n",
    "        self.k = k\n",
    "    def fit(self, X, y):\n",
    "        self.X = np.asarray(X) \n",
    "        self.y = np.asarray(y)\n",
    "    def predict(self, X):\n",
    "        X = np.asarray(X)\n",
    "        result = []\n",
    "        for x in X:\n",
    "            dis = np.sqrt(np.sum((x-self.X)**2, axis=1)) \n",
    "            index = dis.argsort()\n",
    "            index = index[:self.k] \n",
    "            count = np.bincount(self.y[index]) \n",
    "            result.append(count.argmax()) \n",
    "        return np.asarray(result)\n",
    "\n",
    "knn = KNN(k=30)\n",
    "knn.fit(X=train_X, y=train_y)\n",
    "result = knn.predict(test_X)\n",
    "\n",
    "\n",
    "# \"Iris-versicolor\":0,\"Iris-setosa\":1,\"Iris-virginica\":2\n",
    "\n",
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "#默认情况下，matplotlib不支持中文\n",
    "#设置字体为黑体，设置在中文字体时候，能够正常显示符号\n",
    "mpl.rcParams[\"font.family\"]=\"SimHei\"\n",
    "mpl.rcParams[\"axes.unicode_minus\"]=False\n",
    "\n",
    "# \"Iris-versicolor\":0,\"Iris-setosa\":1,\"Iris-virginica\":2\n",
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "plt.figure(figsize=(20,10))\n",
    "mpl.rcParams[\"font.family\"] = 'SimHei' # 默认mpl不支持中文，设置一下支持 \n",
    "mpl.rcParams[\"axes.unicode_minus\"] = False # 设置中文字体是可以正常显示负号\n",
    "plt.scatter(x=t0[\"Sepal.Length\"][:40], y=t0[\"Petal.Length\"][:40], color='r', label=\"Iris-versicolor\")\n",
    "plt.scatter(x=t1[\"Sepal.Length\"][:40], y=t1[\"Petal.Length\"][:40], color='g', label=\"Iris-setosa\")\n",
    "plt.scatter(x=t2[\"Sepal.Length\"][:40], y=t2[\"Petal.Length\"][:40], color='b', label=\"Iris-virginica\")\n",
    "right = test_X[result == test_y]\n",
    "wrong = test_X[result != test_y]\n",
    "plt.scatter(x=right[\"Sepal.Length\"], y=right[\"Petal.Length\"], color='c', label=\"right\", marker=\">\")\n",
    "plt.scatter(x=wrong[\"Sepal.Length\"], y=wrong[\"Petal.Length\"], color='m', label=\"wrong\", marker=\"x\")\n",
    "plt.xlabel('花萼长度')\n",
    "plt.ylabel('花瓣长度')\n",
    "plt.title('KNN分类结果')\n",
    "plt.legend(loc='best')\n",
    "plt.show()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "print(int(3/2))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch_gpu",
   "language": "python",
   "name": "tf-gpu"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
